'Copyright 2006 James Downey

Imports System.Xml

Public Class Condition

    '  <!--
    '  condition element - used for capturing entity and linked-entity
    '            "where" clause criteria
    '-->
    '  <ElementType name='value' content='textOnly' model='closed' />
    '  <ElementType name='condition' content='eltOnly' model='closed'>
    '  <AttributeType name='attribute' dt:type='string' required='yes' />
    '  <AttributeType name='operator' dt:type='enumeration' 
    '                 dt:values='lt gt le ge eq ne null not-null in not-in between 
    '                 not-between like not-like yesterday today tomorrow 
    '                 next-seven-days last-seven-days next-week last-week this-month 
    '                 last-month next-month on on-or-before on-or-after this-year 
    '                 last-year next-year eq-userid ne-userid eq-businessid 
    '                 ne-businessid last-x-hours next-x-hours last-x-days next-x-days
    '                 last-x-weeks next-x-weeks last-x-months next-x-months 
    '                 last-x-years next-x-years' required='yes' default='eq' />
    '  <AttributeType name='value' dt:type='string' required='no' />
    '  <AttributeType name='aggregate' dt:type='enumeration' 
    '                 dt:values='count' required='no' />
    '  <AttributeType name='alias' dt:type='string' required='no' />
    '  <!-- -->
    '
    '  <attribute type='attribute' />
    '  <attribute type='operator' />
    '  <attribute type='value' />
    '  <attribute type='aggregate' />
    '  <attribute type='alias' />
    '  <element type='value' minOccurs='0' maxOccurs='*' />
    '       <!--
    '           The attribute "value" is used for all operators that need to compare against a single value such as eq.
    '           The element "value" is used for operators that need to compare against
    '           multiple values such as in.
    '           Some operators require neither the attribute "value" or the element "value" 
    '           such as null.
    '       -->
    '</ElementType>

    Public Attribute As String
    Public ConditionOperator As String = "eq" 'operator
    Private mValues As Values
    Public Aggregate As Boolean = False
    Public AttributeAlias As String = "" 'alias

    Public Sub New()
        mValues = New Values()
    End Sub

    Public Sub New(ByVal ConditionNode As XmlNode)
        Me.New()
        Me.Attribute = ConditionNode.Attributes("attribute").Value
        Me.ConditionOperator = ConditionNode.Attributes("operator").Value
        If Not ConditionNode.Attributes("alias") Is Nothing Then
            Me.AttributeAlias = ConditionNode.Attributes("alias").Value
        End If
        Select Case GetValueType(ConditionOperator)
            Case ValueType.OneValue
                Me.Values.Add(ConditionNode.Attributes("value").Value)
            Case ValueType.MultipleValues, ValueType.TwoValues
                Dim valuenode As XmlNode
                Dim valuenodes As XmlNodeList
                valuenodes = ConditionNode.SelectNodes("./value")
                For Each valuenode In valuenodes
                    Me.Values.Add(valuenode.InnerText)
                Next
        End Select
    End Sub

    Public ReadOnly Property Values() As Values
        Get
            Return mValues
        End Get
    End Property

    'Public ReadOnly Property ValueType() As ValueType
    '    Get
    '        Return GetValueType(ConditionOperator)
    '    End Get
    'End Property

    Public Shared Function GetValueType(ByVal ConditionOperator As String) As ValueType
        Select Case ConditionOperator
            Case "null", "not-null", "yesterday", "today", "tomorrow", "next-seven-days", "last-seven-days", _
                 "next-week", "last-week", "this-week", "this-month", "last-month", "next-month", "this-year", _
                 "last-year", "next-year", "eq-userid", "ne-userid", "eq-businessid", "ne-businessid"
                Return ValueType.NoValue
            Case "eq", "ne", "lt", "gt", "le", "ge", "like", "not-like", "on", "on-or-before", _
                 "on-or-after", "last-x-hours", "next-x-hours", "last-x-days", "next-x-days", "last-x-weeks", "next-x-weeks", "last-x-months", _
                 "next-x-months", "last-x-years", "next-x-years"
                Return ValueType.OneValue
            Case "between", "not-between"
                Return ValueType.TwoValues
            Case "in", "not-in"
                Return ValueType.MultipleValues
        End Select
    End Function

    Public Overrides Function ToString() As String
        Dim strCondition As String
        If Not AttributeAlias Is Nothing AndAlso AttributeAlias.Length > 0 Then
            strCondition = AttributeAlias
        Else
            strCondition = Attribute
        End If
        strCondition &= " " & ConditionOperator
        Select Case GetValueType(ConditionOperator)
            Case ValueType.OneValue
                strCondition &= " " & Me.Values(0)
            Case ValueType.TwoValues
                strCondition &= " " & Me.Values(0) & " and " & Me.Values(1)
            Case ValueType.MultipleValues
                strCondition &= " ("
                Dim value As String
                Dim values As String = ""
                For Each value In Me.Values
                    If values.Length > 0 Then
                        values &= ","
                    End If
                    values &= value
                Next
                strCondition &= values & ")"
        End Select
        Return strCondition
    End Function

    Public Function ToXML() As String
        Dim strXML As String
        strXML = "<condition attribute='" & Attribute & "' "
        strXML &= "operator='" & Trim(ConditionOperator) & "' "
        If AttributeAlias.Length > 0 Then
            strXML &= "alias='" & Trim(AttributeAlias) & "' "
        End If
        If Me.Aggregate Then
            strXML &= "aggretage='true'"
        End If
        Select Case GetValueType(Me.ConditionOperator)
            Case ValueType.NoValue
                strXML &= "/>"
            Case ValueType.OneValue
                strXML &= "value='" & XMLFormatting.Format(Values(0)) & "'/>"
            Case ValueType.TwoValues
                strXML &= "><value>" & XMLFormatting.Format(Values(0)) & "</value><value>" & XMLFormatting.Format(Values(1)) & "</value></condition>"
            Case ValueType.MultipleValues
                Dim value As String
                strXML &= ">"
                For Each value In Values
                    strXML &= "<value>" & XMLFormatting.Format(value) & "</value>"
                Next
                strXML &= "</condition>"
        End Select
        Return strXML
    End Function

End Class

Public Enum ValueType
    NoValue
    OneValue
    TwoValues
    MultipleValues
End Enum



